# -*- mode: python; coding: utf-8; -*-
##--------------------------------------------------------------------------##
##
## Copyright (C) 1998-2003 Markus Oberhumer <markus@oberhumer.com>
## Copyright (C) 2003 Mt. Hood Playing Card Co.
## Copyright (C) 2005-2010 Skomoroh <skomoroh@users.sourceforge.net>
## Copyright (C) 2010-2013 Jeremy Austin-Bardo <tjaustinbardo@gmail.com>
##
## This program is free software: you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation, either version 3 of the License.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program.  If not, see <http://www.gnu.org/licenses/>.
##
##--------------------------------------------------------------------------##
"""
PIL Image support for easier manipulation images.
"""
import Image
import ImageOps


class NPSImage(object):
    """
    Abstract Image with PIL based methods.
    """
    _orig_pil_image = None
    _pil_image = None

    @property
    def size(self):
        """
        size -> seq(int, int)

        Current **pil_image** size.
        """
        if self._pil_image is not None:
            return self._pil_image.size
        else:
            return 0, 0

    @property
    def menu_image(self):
        """
        _menu_image -> PilImage

        Returns image resized for menu.
        """
        width, height = self._pil_image.size
        ratio = max(2, max(width / 40, height / 60))
        return self.subsample(ratio)

    @property
    def _shade_image(self):
        """
        _shade_image -> PilImage

        Returns image shaded for canvas.
        """
        image = self._pil_image
        shade = Image.new('RGBA', image.size, '#3896f8')
        shade.putalpha(100)
        return self.update_image(image=Image.composite(shade, image, image))

    #@property
    #def _mark_image(self):
    #    """
    #    _mark_image -> PilImage

    #    Returns image marked for canvas.
    #    """
    #    image = self._pil_image
    #    mark = Image.new('RGBA', image.size, '#6ae400')
    #    mark = Image.blend(image, mark, 0.3)
    #    return PilImage(image=Image.composite(mark, image, image))

    def subsample(self, ratio):
        """
        subsample(ratio:int) -> PilImage

        Returns image shaded for canvas.
        """
        image = self._pil_image
        width, height = image.size
        size = int(width / ratio), int(height / ratio)
        return self.update_image(image=image.resize(size))

    def resize(self, xfactor, yfactor):
        """
        resize(xfactor:int, yfactor:int) -> PilImage

        Returns image shaded for canvas saving original.
        """
        width, height = self._orig_pil_image.size
        size = int(width * xfactor), int(height * yfactor)
        image = self._pil_image.resize(size, Image.ANTIALIAS)
        image = self.update_image(image=image)
        image._orig_pil_image = self._orig_pil_image
        return image

    def squeeze(self, nframe, delta):
        """
        squeeze(nframe:int, delta:int) -> PilImage

        Returns image squeezing at **nframe** with **delta** to squeeze for
        animation on canvas saving original. ?DOUBLE CHECK?
        """
        size = self._pil_image.size
        size = tuple(max(0, int(s - nframe * d))
                            for s, d in zip(size, delta))
        image = self._pil_image.resize(size, Image.ANTIALIAS)
        image = self.update_image(image=image)
        image._orig_pil_image = self._orig_pil_image
        return image

    def stretch(self, size, save_aspect=True):
        """
        stretch(size:int, save_aspect:bool=True) -> PilImage

        Returns image stretching at **size** optional **save_aspect** sizing
        for animation on canvas saving original. ?DOUBLE CHECK?
        """
        image = self._orig_pil_image
        w_width, w_height = size
        i_width, i_height = image.size
        if save_aspect:
            ratio = min(float(i_width) / w_width,
                        float(i_height) / w_height)
            size = int(i_width / ratio), int(i_height / ratio)
        image = image.resize(size, Image.ANTIALIAS)
        image = self.update_image(image=image)
        image._orig_pil_image = self._orig_pil_image
        return image

    @property
    def unavailable(self):
        """
        unavailable -> PilImage

        Returns image shaded with **color** at **factor** for canvas
        saving original.
        """
        image = self._orig_pil_image
        d_image = ImageOps.grayscale(image)
        shade = Image.new(d_image.mode, d_image.size, '#dedede')
        tmp = Image.blend(d_image, shade, 0.7)
        d_image = Image.composite(tmp, image, image)
        image = self.update_image(image=d_image)
        image._orig_pil_image = self._orig_pil_image
        return image

    @staticmethod
    def new_image(size, fill=None, outline=None, linewidth=1):
        """
        new_image(size:int, fill:str=None, outline:str=None,
          linewidth:int=1) -> PilImage

        Returns image of **size** with **fill** and **outline** for canvas.
        Size of **outline** is **linewidth**.
        """
        if fill is None and outline is None:
            return
        width, height = size
        if width <= 2 * linewidth or height <= 2 * linewidth:
            fill = fill or outline
            outline = None
        image = Image.new('RGBA', (width, height), outline)
        if fill is not None:
            left = top = linewidth
            bottom = height - 2 * linewidth
            right = width - 2 * linewidth
            image.paste(fill, (left, top, right, bottom))
        return self.update_image(image=image)

    def new_bottom(self, path=None, color='#ffffff', linewidth=1):
        """
        new_bottom(path:str=None, color:str='#ffffff', linewidth:int=1)
          -> PilImage

        Returns image of current **size** with **fill** and optional image
        from **path** inset by **linewidth**.
        """
        img = self._pil_image
        size = img.size
        image = Image.composite(Image.new('RGBA', size, color), img, img)
        r_size = tuple(i - linewidth * 2 for i in size)
        tmp = Image.new('RGBA', r_size, color)
        tmp.putalpha(60)
        mask = image.resize(r_size, Image.ANTIALIAS)
        image.paste(tmp, (linewidth * 2, linewidth * 2), mask)
        if path is not None:
            b_img = self.update_image(Image.open(path).convert('RGBA'))
            b_size = b_img._pil_image.size
            aspect = min(float(i) / j for i, j in zip(size, b_size)) * 0.9
            b_size = tuple(int(i * aspect) for i in b_size)
            back = b_img._pil_image.resize(b_size, Image.ANTIALIAS)
            coords = tuple((i - j) / 2 for i, j in zip(size, b_size))
            image.paste(back, coords, back)
        return self.update_image(image=image)